#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>
#include <unistd.h>

const static int gmaxcap=500;

template<class T>
class BlockQueue
{
public:
    BlockQueue(const int &maxcap=gmaxcap)
    :_maxcap(gmaxcap)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_pcond,nullptr);
        pthread_cond_init(&_ccond,nullptr);
    }

    void push(const T &in) //输入型参数 const&
    {
        pthread_mutex_lock(&_mutex);
        while(is_full()) //伪唤醒，使用while进行持续判断
        {
            pthread_cond_wait(&_pcond,&_mutex); //生产条件不满足，生产者进行等待
        }
        //在这里一定不满
        _q.push(in);
        //此时一定有数据,所以唤醒消费者访问
        pthread_cond_signal(&_ccond);
        pthread_mutex_unlock(&_mutex);
        sleep(1);
    }

    void pop(T* out) //输出型参数 *   输入输出型为 &
    {
        pthread_mutex_lock(&_mutex);
        while(is_empty())
        {
            pthread_cond_wait(&_ccond,&_mutex); //生产条件不满足，生产者进行等待
        }
        //在这里一定不为空
        *out = _q.front();
        _q.pop();
        //此时一定有空间,所以唤醒生产者访问
        pthread_cond_signal(&_pcond);
        pthread_mutex_unlock(&_mutex);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_pcond);
        pthread_cond_destroy(&_ccond);
    }
private:
    bool is_empty()
    {
        return _q.empty();
    }

    bool is_full()
    {
        return _q.size()==_maxcap;
    }
private:
    std::queue<T> _q;
    int _maxcap; //队列元素上限
    pthread_mutex_t _mutex;
    pthread_cond_t _pcond; //生产者对应的条件变量
    pthread_cond_t _ccond; //消费者对应的条件变量
};